
/* GCSx
** EDITOR.CPP
**
** Game editor module- basic init, menubar, other top-level functionality
*/

/*****************************************************************************
** Copyright (C) 2003-2006 Janson
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** 
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
*****************************************************************************/

#include "all.h"

// Icon surface
SDL_Surface* iconSurface = NULL;
const string resourceError("Error loading resource/editoricon.bmp");

SDL_Surface* getIconSurface() { start_func
    static int error = 0;

    if ((!iconSurface) && (!error)) {
        string iconFile;
        createFilename(resourceDir->c_str(), FILENAME_EDITORICONS, iconFile);

        iconSurface = SDL_LoadBMP(iconFile.c_str());
        if (iconSurface == NULL) {
            guiErrorBox(resourceError, errorTitleResourceLoad);
            error = 1;
        }
        else {
            // Copy to a surface32 with clear BK
            SDL_Surface* icon32 = createSurface32(iconSurface->w, iconSurface->h);
            sge_FilledRect(icon32, 0, 0, icon32->w, icon32->h, mapColor32(0, 0, 0, 0));
            SDL_SetAlpha(icon32, SDL_SRCALPHA, 255);
            SDL_SetColorKey(iconSurface, SDL_SRCCOLORKEY, SDL_MapRGB(iconSurface->format, 255, 0, 0));
            blit(0, 0, iconSurface, 0, 0, icon32);
            SDL_FreeSurface(iconSurface);
            iconSurface = icon32;
        }
    }
    return iconSurface;
}

// Menu tree for editor
PopupMenu::PopupGen editorMenuTree[] = {
    { MENU_SUB, "\tWorld", 0 },
        { FILE_NEW, "\tNew", 0 },
        { FILE_OPENEXIST, "\tOpen...", 0 },
        { MENU_SEP, NULL, 0 },
        { FILE_SAVE, "\tSave", 1 },
        { FILE_SAVEAS, "Save \tas...", 1 },
        { FILE_SAVEALL, "Sa\tve all", 0 },
        { MENU_SEP, NULL, 0 },
        { FILE_CLOSE, "\tClose", 1 },
        { FILE_CLOSEALL, "C\tlose all", 0 },
        { MENU_SEP, NULL, 0 },
        { FILE_QUIT, "\tQuit editor", 0 },
        { FILE_EXIT, "E\txit", 0 },
        { 0, NULL, 0 },
    { MENU_SUB, "\tNew", 0 },
        { NEW_ANIM, "Animation Group...", 0 },
        { NEW_FONT, "Font...", 0 },
        { NEW_LIBRARY, "Function Library...", 0 },
        { NEW_IMAGE, "Image/Tile Set...", 0 },
        { NEW_NOTES, "Notes...", 0 },
        { NEW_SCENE, "Scene...", 0 },
        { NEW_SCRIPT, "Script...", 0 },
        { MENU_SEP, NULL, 0 },
        { MENU_SUB, "Import", 0 },
            { NEW_IMPORT_IMAGE, "Image/Tile Set...", 0 },
            { NEW_IMPORT_FONT, "Font...", 0 },
            { 0, NULL, 0 },
        { MENU_SEP, NULL, 0 },
        { NEW_FOLDER, "Folder...", 0 },
        // @TODO: Layer
        // @TODO: World?
        { 0, NULL, 0 },
    { MENU_SUB, "\tEdit", 0 },
        { EDIT_UNDO, "\tUndo", 1 },
        { EDIT_REDO, "\tRedo", 1 },
        { MENU_SEP, NULL, 0 },
        { EDIT_CUT, "Cu\tt", 1 },
        { EDIT_COPY, "\tCopy", 1 },
        { EDIT_PASTE, "\tPaste", 1 },
        { EDIT_DELETE, "\tDelete", 1 },
        { MENU_SEP, NULL, 0 },
        /* Not completed yet
        { EDIT_FLIP, "Flip", 1 },
        { EDIT_MIRROR, "Mirror", 1 },
        { EDIT_SIZEROTATE, "Resize/rotate...", 1 },
        { EDIT_COLORIZE, "Colorize...", 1 },
        { EDIT_FILTER, "Filter...", 1 },
        { MENU_SEP, NULL, 0 },
        */
        { EDIT_SELECTALL, "\tSelect all", 1 },
        { EDIT_DESELECTALL, "\tDeselect all", 1 },
        { MENU_SEP, NULL, 0 },
        { EDIT_GRADIENT, "Create gradient", 1 },
        { EDIT_SETGLYPHWIDTH, "Set \tglyph width", 1 },
        { 0, NULL, 0 },
    { MENU_SUB, "\tTools", 0 },
        { MODE_EDITTILES, "Edit \ttile images", 1 },
        { MODE_EDITCOLLISION, "Edit \tcollision maps", 1 },
        { MODE_EDITASSIGN, "\tAssign maps to tiles", 1 },
        { TOOLS_CHOOSE, "\tChoose...", 1 },
        { TOOLS_CHOOSER, "C\thoose right-click...", 1 },
        { MENU_SEP, NULL, 0 },
        { MENU_SUB, "Settin\tgs", TOOLS_SETTINGS },
            { TOOLS_NEXTIMAGE, "\tNext image", 1 },
            { TOOLS_PREVIMAGE, "\tPrevious image", 1 },
            { TOOLS_NEXTCOLOR, "\tNext color", 1 },
            { TOOLS_PREVCOLOR, "\tPrevious color", 1 },
            { TOOLS_EDITCOLOR, "\tEdit color", 1 },
            { MENU_SEP, NULL, 0 },
            { TOOLS_ANTIALIAS, "\tSmoothing (anti-alias)", 1 },
            { TOOLS_CONTIGUOUS, "\tContiguous", 1 },
            { MENU_SEP, NULL, 0 },
            { TOOLS_BLENDUP, "\tIncrease blend", 1 },
            { TOOLS_BLENDDOWN, "\tDecrease blend", 1 },
            { MENU_SEP, NULL, 0 },
            { TOOLS_TOLERANCEUP, "Inc\trease tolerance", 1 },
            { TOOLS_TOLERANCEDOWN, "Decre\tase tolerance", 1 },
            { 0, NULL, 0 },
        { MENU_SEP, NULL, 0 },
        { TOOLS_PEN, "\tPen", 1 },
        { TOOLS_LINE, "\tLine", 1 },
        { TOOLS_RECT, "Recta\tngle", 1 },
        { TOOLS_RECTFILL, "Filled \trectangle", 1 },
        { TOOLS_ELLIPSE, "\tEllipse", 1 },
        { TOOLS_ELLIPSEFILL, "F\tilled ellipse", 1 },
        { TOOLS_FILL, "\tFlood fill", 1 },
        { MENU_SEP, NULL, 0 },
        { TOOLS_SELECT, "\tSelect", 1 },
        { TOOLS_SELECTELLIPSE, "Selec\tt ellipse", 1 },
        { TOOLS_WAND, "Magic \twand", 1 },
        { MENU_SEP, NULL, 0 },
        { TOOLS_DROPPER, "\tDropper", 1 },
        // @TODO: some new tools (sprites)
        { 0, NULL, 0 },
    { MENU_SUB, "\tView", 0 },
        { VIEW_ZOOMIN, "Zoom \tin", 1 },
        { VIEW_ZOOMOUT, "Zoom \tout", 1 },
        { MENU_SEP, NULL, 0 },
        { VIEW_PREV, "\tPrevious", 1 },
        { VIEW_NEXT, "\tNext", 1 },
        { MENU_SEP, NULL, 0 },
        { VIEW_ALLLAYER, "\tShow all layers", 1 },
        { VIEW_DIMLAYER, "\tDim other layers", 1 },
        { VIEW_NOLAYER, "\tHide other layers", 1 },
        { MENU_SEP, NULL, 0 },
        { VIEW_GRID, "Show \tgrid", 1 },
        { MENU_SUB, "Show \tdots", VIEW_DOTS_CHOOSE },
            { VIEW_DOTS_NONE, "\tNo dots", 1 },
            { VIEW_DOTS_TRANS, "\tTransparent as dots", 1 },
            { VIEW_DOTS_ALPHA, "\tAlpha dots", 1 },
            { 0, NULL, 0 },
        { MENU_SEP, NULL, 0 },
        { VIEW_BROWSER, "\tWorld browser", 1 },
        { VIEW_CONSOLE, "\tConsole", 1 },
    /* Removed (not currently working)
        { MENU_SEP, NULL, 0 },
        { VIEW_TOOLPANEL, "\tTool panel", 1 },
        { VIEW_TOOLBAR, "Tool \tbar", 1 },
    */
        { 0, NULL, 0 },
    /* Removed (only had one item)
    { MENU_SUB, "\tConfig", 0 },
        { 0, NULL, 0 },
    */
    { MENU_SUB, "W\tindow", 0 },
        { WINDOW_NEXT, "\tNext", 1 },
        { WINDOW_PREV, "\tPrevious", 1 },
        { MENU_SEP, NULL, 0 },
        { WINDOW_MIN, "\tMinimize", 1 },
        { WINDOW_MAX, "Ma\tximize", 1 },
        { WINDOW_CLOSE, "\tClose", 1 },
        { WINDOW_CLOSEALL, "Close \tall", 1 },
        { WINDOW_CLOSEALLBUT, "Close all \tbut current", 1 },
        { MENU_SEP, NULL, 0 },
        { WINDOW_TILEHORIZ, "Tile \thorizontally", 1 },
        { WINDOW_TILEVERT, "Tile \tvertically", 1 },
        { WINDOW_CASCADE, "Casca\tde", 1 },
    /* Removed (not currently working)
        { MENU_SEP, NULL, 0 },
        { WINDOW_SWITCHPANEL, "\tSwitch panel", 1 },
    */
        { MENU_SEP, NULL, 0 },
        { CONFIG_RESOLUTION, "\tResolution..." },
        { 0, NULL, 0 },
    { 0, NULL, 0 }
};

// World browser
TreeView* worldBrowser = NULL;

// Menu handler for editor
Window::CommandSupport editorCommandSupport(int code) { start_func
    switch (code) {
        case VIEW_BROWSER:
            return (Window::CommandSupport)((worldBrowser->isOpen() ? Window::COMMAND_SELECTED : 0) | Window::COMMAND_CHECKBOX | Window::COMMAND_ENABLE);

        case VIEW_CONSOLE:
            return (Window::CommandSupport)((debugWindow()->isOpen() ? Window::COMMAND_SELECTED : 0) | Window::COMMAND_CHECKBOX | Window::COMMAND_ENABLE);
    }

    return Window::COMMAND_HIDE;
}

// Command handler for editor
int editorHandleGlobalEvents(const SDL_Event* event) { start_func
    WorldEdit* newWorld = NULL;
    string myFile;

    switch (event->type) {
        case SDL_SPECIAL:
            if (event->user.code == SDL_PREQUIT) {
                // Any modified worlds?
                if (!WorldEdit::modifiedAll()) desktop->cancelQuit();
                return 1;
            }
            if (event->user.code == SDL_IDLETIMEOUTSHORT) {
                config->performSave();
                return 1;
            }
            break;
    
        case SDL_COMMAND:
            switch (event->user.code) {
                case FILE_NEW:
                    // (this line doesn't currently throw)
                    newWorld = new WorldEdit();
                    try {
                        // If not OK, cancel creation of world
                        if (!newWorld->propertiesDialog()) {
                            delete newWorld;
                            return 1;
                        }
                        // Can't undo creation of a new world
                        newWorld->undo.clearUndo();
                    }
                    catch (UndoException& e) {
                        delete newWorld;
                        return 1;
                    }

                    newWorld->addToBrowser(worldBrowser);
                    if (!worldBrowser->isOnDesktop()) {
                        worldBrowser->runWindowed();
                    }
                    return 1;
                    
                case FILE_OPENEXIST:
                    try {
                        if (fileOpen(FILETYPE_WORLD, 1, myFile)) {
                            // (exception point)
                            newWorld = new WorldEdit(myFile.c_str());
                            newWorld->addToBrowser(worldBrowser);
                            
                            if (!worldBrowser->isOnDesktop()) {
                                worldBrowser->runWindowed();
                            }
                        }
                    }
                    catch (FileException& e) {
                        guiErrorBox(string(e.details), errorTitleFile);
                    }
                    return 1;
                    
                case FILE_SAVEALL:
                    WorldEdit::saveAll();
                    return 1;
                    
                case FILE_CLOSEALL:
                    WorldEdit::closeAll();
                    return 1;
                    
                case FILE_EXIT:
                    desktop->broadcastEvent(SDL_QUIT, 0);
                    return 1;
                    
                case FILE_QUIT:
                    desktop->broadcastEvent(SDL_SPECIAL, SDL_QUITTOFRONT);
                    return 1;
                    
                case CONFIG_RESOLUTION:
                    ResolutionDialog::create()->chooseResolution();
                    return 1;
                    
                case VIEW_BROWSER:
                    if (worldBrowser->isOnDesktop()) {
                        worldBrowser->closeWindow();
                    }
                    else {
                        worldBrowser->runWindowed();
                    }
                    return 1;
                    
                case VIEW_CONSOLE:
                    if (debugWindow()->isOpen()) {
                        debugWindow()->closeWindow();
                    }
                    else {
                        debugWindow()->runWindowed();
                    }
                    return 1;
            }
            break;
    }
    
    return 0;
}

int gcsxEditor() { start_func
    PopupMenu* editorMenu = NULL;
    int quitType = 0;
    SDL_Surface* bk;

    try {
        // In the editor, we need unicode translation and repeating keys
        SDL_EnableUNICODE(1);
        SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
    
        // Our event handlers
        desktop->setEventHandler(editorHandleGlobalEvents);
        desktop->setSupportsHandler(editorCommandSupport);

        // Set up items for the "View" menu
        worldBrowser = new TreeView("Browse Worlds", NULL, 0, NULL, 1);
        
        // Set up our menus
        editorMenu = PopupMenu::compileMenu(editorMenuTree, 1);
        editorMenu->menubar(1);
        
        // Background (error results in quietly having no bk image)
        string bkFile;
        createFilename(resourceDir->c_str(), FILENAME_BKEDITOR, bkFile);
        bk = IMG_Load(bkFile.c_str());
        desktop->setBackground(bk, COLOR_EDITORDESKTOP);
            
        // Enter main event loop
        SDL_WM_SetCaption(PRODUCT_NAME " - Editor", PRODUCT_NAME " - Editor");
        quitType = desktop->eventLoop();
        
        // Close all windows
        desktop->closeAllWindows();
        
        // Close all worlds
        WorldEdit::closeAll(1);
        
        // Cleanup
        // @TODO: Standardize 3 sets of cleanup into one (don't run beginExitStage() here!)
        desktop->setBackground(NULL, COLOR_EDITORDESKTOP);
        if (iconSurface) {
            SDL_FreeSurface(iconSurface);
            iconSurface = NULL;
        }
        SDL_FreeSurface(bk);
        delete worldBrowser;
        worldBrowser = NULL;
        delete editorMenu;
        editorMenu = NULL;
        desktop->setSupportsHandler(NULL);
        desktop->setEventHandler(NULL);
        desktop->initEventCleanup();
        SDL_EnableKeyRepeat(0, 0);
        SDL_EnableUNICODE(0);
        clearEvents();
    }
    // Any exceptions
    catch (...) {
        try {
            beginExitStage();

            // @TODO: Attempt to recovery-save?
            
            // Cleanup
            desktop->deleteAllWindows();
            desktop->setBackground(NULL, COLOR_EDITORDESKTOP);
            if (iconSurface) {
                SDL_FreeSurface(iconSurface);
                iconSurface = NULL;
            }
            SDL_FreeSurface(bk);
            delete worldBrowser;
            worldBrowser = NULL;
            delete editorMenu;
            desktop->setSupportsHandler(NULL);
            desktop->setEventHandler(NULL);
            desktop->initEventCleanup();
            SDL_EnableKeyRepeat(0, 0);
            SDL_EnableUNICODE(0);
            clearEvents();
        }
        catch (...) {
        }
        // Pass it on
        throw;
    }
    
    return quitType == SDL_QUITTOFRONT;
}

